/**
 * WebSocket 管理类
 * 用于聊天系统的实时通信
 */

export interface WSMessage {
  type: string
  data: any
  timestamp: string
}

export type WSMessageHandler = (message: WSMessage) => void

export class WebSocketManager {
  private ws: WebSocket | null = null
  private url: string
  private token: string
  private reconnectAttempts = 0
  private maxReconnectAttempts = 5
  private reconnectDelay = 3000
  private heartbeatInterval: number | null = null
  private messageHandlers: Map<string, Set<WSMessageHandler>> = new Map()
  private isManualClose = false

  constructor(url: string, token: string) {
    this.url = url
    this.token = token
  }

  /**
   * 连接 WebSocket
   */
  connect(): Promise<void> {
    return new Promise((resolve, reject) => {
      try {
        const wsUrl = `${this.url}?token=${this.token}`
        this.ws = new WebSocket(wsUrl)

        this.ws.onopen = () => {
          console.log('[WebSocket] 连接成功')
          this.reconnectAttempts = 0
          this.startHeartbeat()
          resolve()
        }

        this.ws.onmessage = (event) => {
          try {
            const message: WSMessage = JSON.parse(event.data)
            console.log('[WebSocket] 收到消息:', message)
            this.handleMessage(message)
          } catch (error) {
            console.error('[WebSocket] 解析消息失败:', error)
          }
        }

        this.ws.onerror = (error) => {
          console.error('[WebSocket] 连接错误:', error)
          reject(error)
        }

        this.ws.onclose = (event) => {
          console.log('[WebSocket] 连接关闭:', event.code, event.reason)
          this.stopHeartbeat()

          // 如果不是手动关闭，尝试重连
          if (!this.isManualClose && this.reconnectAttempts < this.maxReconnectAttempts) {
            this.reconnectAttempts++
            console.log(`[WebSocket] 尝试重连 (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`)
            setTimeout(() => {
              this.connect()
            }, this.reconnectDelay)
          }
        }
      } catch (error) {
        console.error('[WebSocket] 创建连接失败:', error)
        reject(error)
      }
    })
  }

  /**
   * 断开连接
   */
  disconnect() {
    this.isManualClose = true
    this.stopHeartbeat()
    if (this.ws) {
      this.ws.close()
      this.ws = null
    }
  }

  /**
   * 发送消息
   */
  send(type: string, data: any) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
      console.error('[WebSocket] 连接未就绪')
      return
    }

    const message: WSMessage = {
      type,
      data,
      timestamp: new Date().toISOString()
    }

    this.ws.send(JSON.stringify(message))
    console.log('[WebSocket] 发送消息:', message)
  }

  /**
   * 注册消息处理器
   */
  on(messageType: string, handler: WSMessageHandler) {
    if (!this.messageHandlers.has(messageType)) {
      this.messageHandlers.set(messageType, new Set())
    }
    this.messageHandlers.get(messageType)!.add(handler)
  }

  /**
   * 移除消息处理器
   */
  off(messageType: string, handler: WSMessageHandler) {
    const handlers = this.messageHandlers.get(messageType)
    if (handlers) {
      handlers.delete(handler)
    }
  }

  /**
   * 处理收到的消息
   */
  private handleMessage(message: WSMessage) {
    const handlers = this.messageHandlers.get(message.type)
    if (handlers) {
      handlers.forEach(handler => {
        try {
          handler(message)
        } catch (error) {
          console.error('[WebSocket] 消息处理器执行失败:', error)
        }
      })
    }

    // 全局处理器
    const globalHandlers = this.messageHandlers.get('*')
    if (globalHandlers) {
      globalHandlers.forEach(handler => {
        try {
          handler(message)
        } catch (error) {
          console.error('[WebSocket] 全局消息处理器执行失败:', error)
        }
      })
    }
  }

  /**
   * 开始心跳
   */
  private startHeartbeat() {
    this.heartbeatInterval = window.setInterval(() => {
      this.send('PING', {})
    }, 30000) // 每30秒发送一次心跳
  }

  /**
   * 停止心跳
   */
  private stopHeartbeat() {
    if (this.heartbeatInterval) {
      clearInterval(this.heartbeatInterval)
      this.heartbeatInterval = null
    }
  }

  /**
   * 获取连接状态
   */
  get readyState(): number {
    return this.ws?.readyState ?? WebSocket.CLOSED
  }

  /**
   * 是否已连接
   */
  get isConnected(): boolean {
    return this.ws?.readyState === WebSocket.OPEN
  }
}

// 全局 WebSocket 实例
let globalWsInstance: WebSocketManager | null = null

/**
 * 获取全局 WebSocket 实例
 */
export function getWebSocketInstance(url: string, token: string): WebSocketManager {
  if (!globalWsInstance) {
    globalWsInstance = new WebSocketManager(url, token)
  }
  return globalWsInstance
}

/**
 * 销毁全局 WebSocket 实例
 */
export function destroyWebSocketInstance() {
  if (globalWsInstance) {
    globalWsInstance.disconnect()
    globalWsInstance = null
  }
}

